﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Windows.Controls.Ribbon;
using SHomeWorkshop.LunarConcept.Controls;
using System.Xml;
using SHomeWorkshop.LunarConcept.Tools;
using SHomeWorkshop.LunarConcept.ModifingManager;
using System.Windows;
using SHomeWorkshop.LunarConcept.Widgets;
using SHomeWorkshop.LunarConcept.Widgets.Interfaces;

namespace SHomeWorkshop.LunarConcept.Commands
{
    /// <summary>
    /// 创建时间：2012年1月17日
    /// 创建者：  杨震宇
    /// 
    /// 主要用途：删除当前选定的所有部件。
    /// </summary>
    public static class DeleteWidgetsCommand
    {
        #region 构造方法=====================================================================================================

        /// <summary>
        /// [静态][构造方法]
        /// 
        /// ——此方法会初始化并向WPF系统注册一个RoutedUICommand。
        /// </summary>
        static DeleteWidgetsCommand()//类型构造器
        {
            routedUICmd = new RoutedUICommand(
                "DeleteWidgetsCommand",
                "DeleteWidgetsCommand",
                typeof(DeleteWidgetsCommand),//创建RoutedUICommand对象
                null);

            routedUICmd.InputGestures.Add(new KeyGesture(Key.Delete, ModifierKeys.None, "Delete"));

            cmdBinding.Command = routedUICmd;
            cmdBinding.CanExecute += new CanExecuteRoutedEventHandler(cmdBinding_CanExecute);
            cmdBinding.Executed += new ExecutedRoutedEventHandler(cmdBinding_Executed);
        }

        #endregion

        #region 字段与属性===================================================================================================

        private static CommandBinding cmdBinding = new CommandBinding();
        /// <summary>
        /// 用在主窗口CommandBindings集合中的命令绑定。
        /// 
        /// 它的Command是RoutedUICommand。
        /// ——因此，RoutedUICommand是否可以运行将由CmdBinding的CanExecute事件决定。
        /// ——而且，RoutedUICommand的执行也是通过CmdBinding的Execute事件来进行的。
        /// </summary>
        public static CommandBinding CmdBinding
        {
            get { return cmdBinding; }
        }

        private static RoutedUICommand routedUICmd;
        /// <summary>
        /// [只读静态属性]表示在WPF系统中注册的一个RoutedUICommand。
        /// ——必须和CommandBinding配合才能使用。
        ///     CommandBinding要添加到主窗口的CommandBindings集合中；
        ///     RoutedUICommand则要向WPF系统注册。
        ///     
        /// ★说明：使用静态属性是因为这样在Xaml代码中比较便于绑定。
        /// </summary>
        public static RoutedUICommand RoutedUICmd
        {
            get { return routedUICmd; }
        }

        #endregion

        #region 方法=========================================================================================================

        /// <summary>
        /// 判断命令是否可以执行。
        /// ——由于可以直接调用Execute()方法，因此，即使被禁用，也不是不能执行相关功能！！！
        /// </summary>
        static void cmdBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            //考虑到性能问题，全部取消此判断。反正执行时会判断。
            //if (Globals.MainWindow == null)
            //{
            //    e.CanExecute = false; return;
            //}

            //EditorManager manager = Globals.MainWindow.EditorManager;
            //if (manager == null)
            //{
            //    e.CanExecute = false; return;
            //}

            //int selectedWidgetsCount = manager.GetSelectedWidgetsCount();

            //if (selectedWidgetsCount > 0)
            //{
            //    e.CanExecute = true; return;
            //}

            e.CanExecute = true;
            return;
        }

        /// <summary>
        /// 命令被触发时，会调用本事件处理器方法。
        /// ——本方法实际上是调用ExeCute()这个静态方法来实现特定功能。
        /// </summary>
        static void cmdBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            LunarMessage.Warning(Execute());
        }

        /// <summary>
        /// [公开静态方法]即使此命令处于禁用状态，也可以通过代码调用此方法来执行特定任务！！！
        /// 
        /// 当被绑定的命令被调用（触发）时，会引发cmdBinding_Executed事件。
        /// 在cmdBinding_Executed事件处理器方法中已添加了调用Execute()方法的代码。
        /// 
        /// ——因此，触发命令，就相当于调用此方法！！！
        /// </summary>
        public static string Execute(bool copyToClipboard = false)
        {
            if (Globals.MainWindow == null) return "　　未找到Globals.MainWindow。";
            if (Globals.MainWindow.EditorManager == null) return "　　未找到页面管理器。";
            EditorManager manager = Globals.MainWindow.EditorManager;
            if (manager.GetAllPageEditors().Count <= 0) return "　　页面管理器中无页面。";

            List<Widgets.Widget> selectedWidgets = manager.GetSelectedWidgetsList();
            if (selectedWidgets.Count <= 0) return "　　未选定部件";

            ModifingInfo info = new ModifingInfo();
            manager.GetSelectedPageEditorStatus(info);
            manager.GetSelectedWidgetStatus_Old(info);

            PageEditor peFst = selectedWidgets[0].MasterEditor;

            if (copyToClipboard)
            {
                info.ModifingDescription = "剪切部件";
                for (int i = 1; i < selectedWidgets.Count; i++)
                {
                    if (selectedWidgets[i].MasterEditor != peFst)
                    {
                        return "　　不允许跨页面剪切与复制！";
                    }
                }
            }
            else
            {
                info.ModifingDescription = "删除部件";
            }

            //不相干的关系线，只要选定即会被删除！！！这与组合不同！与复制也不同。
            //因为剪切与删除共用同一代码逻辑，因此，必须改造粘贴操作，以防止粘贴不相干的连接线。
            //也就是说，不相干连接线，可删除、可剪切、但不能粘贴。

            List<ILinkableLine> onlyDeleteLinkedLines = new List<ILinkableLine>();

            for (int i1 = selectedWidgets.Count - 1; i1 >= 0; i1--)
            {
                ILinkableLine linkedLine = selectedWidgets[i1] as ILinkableLine;
                if (linkedLine == null || linkedLine.IsLinked == false) continue;

                bool startLinked = false; bool endLinked = false;
                for (int i2 = selectedWidgets.Count - 1; i2 >= 0; i2--)
                {
                    if (linkedLine.StartMasterId == selectedWidgets[i2].Id) { startLinked = true; }

                    if (linkedLine.EndMasterId == selectedWidgets[i2].Id) { endLinked = true; }
                }

                if (startLinked == false || endLinked == false)
                {
                    selectedWidgets.Remove(linkedLine as Widgets.Widget);
                    //选定的某个连接线至少有一个点与选定的所有ContentWidget都不相干。
                    onlyDeleteLinkedLines.Add(linkedLine);
                }
            }

            List<ILinkableLine> allLinkedLines = new List<ILinkableLine>();
            List<ILinkableLine> startLinkedLines = new List<ILinkableLine>();
            List<ILinkableLine> endLinkedLines = new List<ILinkableLine>();

            peFst.GetLinkdeLines(selectedWidgets, ref allLinkedLines, ref startLinkedLines, ref endLinkedLines);

            //两个挂接部件都被选定了，关系线没选定也当选定处理。
            foreach (ILinkableLine linkedLine in allLinkedLines)
            {
                if (selectedWidgets.Contains(linkedLine as Widget) == false)
                    selectedWidgets.Add(linkedLine as Widget);
            }

            ModifingItem<Action, ModifingInfo> mi = new ModifingItem<Action, ModifingInfo>(info);
            #region 无论是否复制到剪贴板，都需要取出“删除区”的尺寸。
            //注意：如果只选定了连接线，则selectedWidgets.Count为0，这样“删除区”的尺寸也就取不出来了。

            Rect deleteArea = new Rect(0, 0, 0, 0);

            if (selectedWidgets.Count > 0)
            {

                double minLeft = double.MaxValue;
                double minTop = double.MaxValue;
                double maxRight = 0;
                double maxBottom = 0;

                foreach (Widgets.Widget w in selectedWidgets)
                {
                    if (w.TopLeft.X < minLeft) minLeft = w.TopLeft.X;

                    if (w.TopLeft.Y < minTop) minTop = w.TopLeft.Y;

                    double right = w.TopLeft.X + w.ActualWidth;
                    if (right > maxRight) maxRight = right;

                    double bottom = w.TopLeft.Y + w.ActualHeight;
                    if (bottom > maxBottom) maxBottom = bottom;
                }

                deleteArea.X = minLeft;
                deleteArea.Y = minTop;
                deleteArea.Width = maxRight - minLeft;
                deleteArea.Height = maxBottom - minTop;

                #endregion

                if (copyToClipboard)
                {
                    //要复制到剪贴板，所以要按层级正充排列
                    selectedWidgets.Sort(new WidgetLayerAZCompareClass());

                    StringBuilder sb = new StringBuilder();
                    sb.Append("<LunarConcept.Copy Width=\"" + deleteArea.Width.ToString() + "\" " +
                        "Height=\"" + deleteArea.Height.ToString() + "\" >");

                    Point baseCopyLeftTop = new Point(minLeft, minTop);

                    foreach (Widgets.Widget w in selectedWidgets)
                    {
                        if (w.XmlData != null)
                        {
                            string oldLocation = w.XmlData.GetAttributeValueText(XmlTags.LocationTag);
                            Widgets.LineWidget lw = w as Widgets.LineWidget;
                            if (lw != null)
                            {
                                sb.Append(lw.GetRelativeOuterXml(baseCopyLeftTop));
                            }
                            else
                            {
                                ContentWidget cw = w as ContentWidget;
                                if (cw != null)
                                {
                                    cw.XmlData.SetAttribute(XmlTags.LocationTag,
                                        new Point(cw.Location.X - minLeft, cw.Location.Y - minTop).ToString());
                                    sb.Append(cw.XmlData.OuterXml);
                                    cw.XmlData.SetAttribute(XmlTags.LocationTag, oldLocation);//还原
                                }
                            }
                        }
                    }

                    sb.Append("</LunarConcept.Copy>");

                    try
                    {
                        Clipboard.SetData(DataFormats.UnicodeText, sb.ToString());
                    }
                    catch (Exception ex)
                    {
                        return "　　发生意外，未能向剪贴板写入文本！系统剪贴板可能被其它程序占用。" +
                            "异常信息如下：\r\n" + ex.Message + "\r\n" + ex.StackTrace;
                    }
                }
            }

            int titleWidgetsCount = 0;

            //为保证撤销“删除操作”后部件层级正确，这里需要倒序排列。
            selectedWidgets.Sort(new WidgetLayerZACompareClass());

            foreach (Widgets.Widget w in selectedWidgets)
            {
                if (w.TitleLevel != Enums.TitleStyle.Normal) titleWidgetsCount++;

                if (w.MasterEditor == null) continue;

                Action actDeleteWidget = new Action(ActionType.WidgetDeleted,
                    w.MasterEditor.Id, w.Id, w.XmlData.OuterXml, null);

                if (w.XmlData != null && w.XmlData.ParentNode != null)
                {
                    XmlNode widgetSetNode = w.XmlData.ParentNode;
                    widgetSetNode.RemoveChild(w.XmlData);
                }

                if (w.MasterEditor != null)
                {
                    w.MasterEditor.RemoveWidget(w);
                }

                mi.AddAction(actDeleteWidget);
            }

            DeleteLinkedLines(onlyDeleteLinkedLines, mi);
            DeleteLinkedLines(startLinkedLines, mi);
            DeleteLinkedLines(endLinkedLines, mi);

            manager.RegisterModifingItem(mi);

            if (manager.MasterWindow != null)
            {
                manager.MasterWindow.CTGWidgetFormContextualTabGroup.Visibility = Visibility.Collapsed;//删除后不会自动选定。
                //manager.MasterWindow.CTGOutBorderFormContextualTabGroup.Visibility = Visibility.Collapsed;//删除后不会自动选定。
                manager.MasterWindow.CTGEllipseColorSolution.Visibility =
                    manager.MasterWindow.CTGRectangleWidgetColorSolution.Visibility =
                    manager.MasterWindow.CTGTriangleFormTabGroup.Visibility = Visibility.Collapsed;
            }

            if (titleWidgetsCount > 0)
            {
                manager.RefreshAutoNumberStrings();
                mi.NeedRefreshAutoNumberStrings = true;
            }

            //跳转到被删除的部件顶部的一定范围内最先找到的部件。
            if (deleteArea.Width > 0 && deleteArea.Height > 0)
            {
                if (deleteArea.Y > 0)//删除区域顶边如果太近页面顶端，说明上面不可能有部件，不跳转
                {
                    Rect searchRect = new Rect(0, 0, peFst.ActualWidth, deleteArea.Y);
                    //找到删除区顶端到页面顶端最靠下的一个部件。
                    List<Widgets.Widget> widgetsInArea = peFst.GetWidgetsInArea(searchRect, true);

                    if (widgetsInArea.Count > 0)
                    {
                        widgetsInArea[widgetsInArea.Count - 1].SelectOnlySelf();
                        info.NewMainSelectedWidgetID = widgetsInArea[widgetsInArea.Count - 1].Id;
                    }
                    else
                    {
                        if (peFst.ActualHeight >= deleteArea.Bottom)
                        {
                            widgetsInArea = peFst.GetWidgetsInArea(
                                new Rect(
                                    searchRect.Left, deleteArea.Bottom, searchRect.Width,
                                    peFst.ActualHeight - deleteArea.Bottom),
                                    true);
                            if (widgetsInArea.Count > 0)
                            {
                                widgetsInArea[0].SelectOnlySelf();
                                info.NewMainSelectedWidgetID = widgetsInArea[0].Id;
                            }
                        }
                    }
                }
            }

            return string.Empty;
        }

        private static void DeleteLinkedLines(List<ILinkableLine> onlyDeleteLinkedLines, ModifingItem<Action, ModifingInfo> mi)
        {
            foreach (ILinkableLine linkedLine in onlyDeleteLinkedLines)
            {
                if (linkedLine.MasterEditor == null) continue;

                Action actDeleteWidget = new Action(ActionType.WidgetDeleted,
                    linkedLine.MasterEditor.Id, linkedLine.Id, linkedLine.XmlData.OuterXml, null);

                if (linkedLine.XmlData != null && linkedLine.XmlData.ParentNode != null)
                {
                    XmlNode widgetSetNode = linkedLine.XmlData.ParentNode;
                    widgetSetNode.RemoveChild(linkedLine.XmlData);
                }

                if (linkedLine.MasterEditor != null)
                {
                    linkedLine.MasterEditor.RemoveWidget(linkedLine as Widget);
                }

                mi.AddAction(actDeleteWidget);
            }
        }

        #endregion
    }
}
